package com.example.demo.web;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.example.demo.mapper.ChatMapper;
import com.example.demo.model.ChatHistory;
import com.example.demo.model.User;
import com.example.demo.service.IChatHistoryService;
import com.example.demo.service.IMessageRankService;
import com.example.demo.service.IRedisOnlineService;
import com.example.demo.service.IUserService;
import com.example.demo.util.SpringContextHolder;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;


/**
 * 说明：
 */
@ServerEndpoint(value = "/chat/{userId}")
@Component
@Slf4j
public class Chat1WebSocket {
    // session缓存
   public   final static ConcurrentHashMap<String ,Session> sessionMap = new ConcurrentHashMap<>();

    public Chat1WebSocket() {
        System.out.println("进入了 Chat1WebSocket 构造方法");
    }
    private static ChatMapper mapper; // 静态注入

    IChatHistoryService getHistoryService(){
        return SpringContextHolder.getBean(IChatHistoryService.class);
    }

    private static IChatHistoryService chatHistoryService;
    private static IUserService userService;
    private  static IRedisOnlineService redisOnlineService;
    private static IMessageRankService messageRankService;
    private static SessionManager sessionManager;
    private static RedisMessagePublisher redisMessagePublisher;
    private  static RateLimiter rateLimiter;


    @Autowired
    public void  setService(
            IChatHistoryService ous,
            IUserService userService,
            IRedisOnlineService iRedisOnlineService,
            IMessageRankService messageRankService,
            RedisMessagePublisher redisMessagePublisher,
            RateLimiter rateLimiter,
            SessionManager sessionManager)
    {
        Chat1WebSocket.redisOnlineService=redisOnlineService;
        Chat1WebSocket.chatHistoryService =ous;
        Chat1WebSocket.userService=userService;
        Chat1WebSocket.messageRankService=messageRankService;
        Chat1WebSocket.redisMessagePublisher =redisMessagePublisher;
        Chat1WebSocket.rateLimiter = rateLimiter;
        Chat1WebSocket.sessionManager=sessionManager;
    }

    @Autowired
    public void setChatMapper(ChatMapper mapper) {
        Chat1WebSocket.mapper = mapper;
    }

    //建立当前websocket连接会话
    @OnOpen
    public void openConn( Session session , @PathParam("userId")String userId) {
        //获得当前会话的唯一标识
        String sessionId = session.getId();
        System.out.println("建立ws连接: " + sessionId);
        User detail = userService.detail(userId);
        if(detail==null){
            doClose(session,"用户id不存在");
            return;
        }
        //redis调用方法将用户标记为在线
        redisOnlineService.loginUser(userId);
        //存储活跃的websocket会话
        sessionMap.put(sessionId, session);

    }
    /*
    *向客户端发送错误信息，并且断开连接
    * @param session session对话
    * @param msg 错误信息
     */

    private void doClose(Session session,String msg){
        try {
            if(StrUtil.isNotBlank(msg)){
                sendMessage(session,msg);
            }
            session.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    /*
    发送文本消息
     */
    private void sendMessage(Session session, String msg) {
        try {
            session.getBasicRemote().sendText(msg);
        } catch (IOException e) {
            log.error("给 ws 客户端: {} 发送消息失败", session.getId(), e);
        }
    }

         /*
        *客户端与服务端websocket的连接关闭
         * 注销用户并更新在线状态。
        *通知其他客户端用户的下线状态。
        *移除会话管理器中的会话信息。
        *记录关闭连接的日志。 */
    @OnClose
    public void onClose(Session session ,CloseReason reason) {
        String sessionId = session.getId();
        String reasonPhrase = reason.getReasonPhrase();
      //会话管理器中移除会话信息
        sessionMap.remove(sessionId); // 确保清理
        log.info("关闭连接: {}, 原因: {}", session, reason.getReasonPhrase());
        System.out.println(String.format("关闭ws连接: %s, reason: %s", sessionId, reasonPhrase));
    }

    /*
      *处理客户端通过websocket发送的消息
      *记录收到的消息日志。
       检查消息发送频率，防止消息轰炸。
       如果会话有效，将消息广播给所有其他客户端。
        解析JSON格式的消息，保存聊天记录，更新消息排行榜，并通过Redis广播消息。
     */
    @OnMessage
    public void echoTextMessage(Session session, String msg) {
        log.info("[websocket消息] 收到 websocket信息：{}", msg);
        String userId = session.getId();
        log.info("收到消息: 用户={}, 内容={}", userId, msg);

        // 添加频率检查
        boolean b = rateLimiter.checkRateLimit(userId);
        if (!b) {
            try {
                //检查用户发送的消息频率是否超过限制
                session.getBasicRemote().sendText("消息发送过于频繁，请稍后再试");
            } catch (IOException e) {
                System.out.println("频率限制消息发送失败");
            }
            return;
        }
        //判断会话是否打开
        if (session.isOpen()) {
            System.out.println("收到ws消息=" + msg);
            //记录消息排行信息
            messageRankService.addMessageCount(userId);
            // 广播消息到redis channel
            redisMessagePublisher.publishMessage(msg);

            //通过redis订阅后，原有广播消息不需要了
//            //遍历所有的会话
//            sessionMap.values().forEach(otherSession -> {
//                try {
//                    // 将收到的消息广播给所有其他客户端
//                    otherSession.getBasicRemote().sendText(msg);
//                } catch (IOException e) {
//                    System.out.println("广播消息发生异常" + e.getMessage());
//                }
//            });
            // 解析用户发送过来的json格式消息内容
            try {
                // 打印原始消息
                System.out.println("原始消息: " + msg);
                // JSON字符串解析JSONObject对象
                JSONObject jsonObject = JSONUtil.parseObj(msg);
                ChatHistory chatHistory = jsonObject.toBean(ChatHistory.class);
               chatHistoryService.add(chatHistory);
            } catch (Exception e) {
                // 打印解析异常
                System.out.println("解析json格式异常，json: " + msg);
                System.out.println("异常信息: " + e.getMessage());
            }
        }
    }
    @OnError
    public void onError(Session session,Throwable throwable){
        System.out.println("发生错误"+throwable.getMessage());
        sessionMap.remove(session);

    }





    // 发送在线用户更新通知
    /*
    html 客户端代码:
    var wsClient = new WebSocket('ws://localhost:8080/chat1/zhangsan/99999')
    wsClient.send('你好吗?')
    wsClient.close()
     */

}
